﻿using Microsoft.Extensions.Logging;
using Quartz.Spi;
using Quartz;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Bean.Quartz.Core
{
    /// <summary>
    /// 定时器启动注册类
    /// </summary>
    public class QuartzStartup
    {
        private ILogger<QuartzStartup> _logger;
        private readonly ISchedulerFactory _factory;
        private readonly IJobFactory _iocFactory;
        private IScheduler _scheduler;

        public bool IsStart { get; private set; } = false;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="logger"></param>
        /// <param name="ioc"></param>
        /// <param name="schedulerFactory"></param>
        public QuartzStartup(ILogger<QuartzStartup> logger, IJobFactory ioc, ISchedulerFactory schedulerFactory)
        {
            _logger = logger;
            _iocFactory = ioc;
            _factory = schedulerFactory;
        }

        /// <summary>
        /// 开启服务
        /// </summary>
        /// <returns></returns>
        public async Task StartAsync()
        {
            _scheduler = await _factory.GetScheduler();
            _scheduler.JobFactory = _iocFactory;
            await _scheduler.Start();
            IsStart = true;
        }

        /// <summary>
        /// 添加瞬时任务
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Name"></param>
        /// <param name="WaitSeconds"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public async Task AddInstantJob<T>(string Name, int WaitSeconds, string key, string value) where T : IJob
        {
            IJobDetail job = JobBuilder.Create<T>().Build();
            ITrigger trigger = TriggerBuilder.Create().WithSimpleSchedule(t => t.WithIntervalInSeconds(WaitSeconds).WithRepeatCount(0)).Build();

            job.JobDataMap.Add("WaitSeconds", WaitSeconds);
            job.JobDataMap.Add(new KeyValuePair<string, object>(key, value));

            _logger.LogInformation($">>>    开启任务[瞬时]<{Name}");

            await _scheduler.ScheduleJob(job, trigger);
        }

        /// <summary>
        /// 添加瞬时任务
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Name"></param>
        /// <param name="WaitSeconds"></param>
        /// <param name="maps"></param>
        /// <returns></returns>
        public async Task AddInstantJob<T>(string Name, int WaitSeconds = 0, List<KeyValuePair<string, object>> maps = null) where T : IJob
        {
            IJobDetail job = JobBuilder.Create<T>().Build();
            ITrigger trigger = TriggerBuilder.Create().WithSimpleSchedule(t => t.WithIntervalInSeconds(WaitSeconds).WithRepeatCount(0)).Build();

            if (maps != null)
            {
                for (int i = 0; i < maps.Count; i++)
                {
                    job.JobDataMap.Add(maps[i].Key, maps[i].Value);
                }
            }

            _logger.LogInformation($">>>    开启任务[瞬时]<{Name}");

            await _scheduler.ScheduleJob(job, trigger);
        }

        /// <summary>
        /// 计划任务是否存在
        /// </summary>
        /// <param name="Name"></param>
        /// <returns></returns>
        public async Task<bool> ExistJob(string Name)
        {
            var jk = JobKey.Create(Name);
            bool exist = await _scheduler.CheckExists(jk);
            if (exist)
            {
                _logger.LogWarning($">>>    任务已存在，无法重复执行 <{Name}>");
                return true;
            }
            return false;
        }

        /// <summary>
        /// 添加定时任务
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="jobInterval"></param>
        /// <param name="val"></param>
        /// <returns></returns>
        public async Task<bool> AddTimerJob<T>(string Name, JobIntervalType jobInterval, int val, List<KeyValuePair<string, string>> maps = null) where T : IJob
        {
            var jk = JobKey.Create(Name);

            //bool exist = await _scheduler.CheckExists(jk);
            //if (exist)
            //{
            //    _logger.LogInformation($">>>    任务已存在，无法重复执行 <{Name}>");
            //    return false;
            //}

            IJobDetail job = JobBuilder.Create<T>().WithIdentity(jk).Build();
            ITrigger trigger = null;

            switch (jobInterval)
            {
                case JobIntervalType.Seconds:
                    trigger = QuartzTriggerUtil.CreateTriggerSeconds(val);
                    break;
                case JobIntervalType.Minutes:
                    trigger = QuartzTriggerUtil.CreateTriggerMinutes(val);
                    break;
                case JobIntervalType.Hours:
                    trigger = QuartzTriggerUtil.CreateTriggerHours(val);
                    break;
            }
            if (maps != null)
            {
                foreach (var t in maps)
                {
                    job.JobDataMap.Add(t.Key, t.Value);
                }
            }

            _logger.LogInformation($">>>    开启任务[定时]<{Name}> {val} {jobInterval}");

            await _scheduler.ScheduleJob(job, trigger);

            return true;
        }

        /// <summary>
        /// 删除任务
        /// </summary>
        /// <param name="Name"></param>
        /// <returns></returns>
        public async Task DelJob(string Name)
        {
            var jk = JobKey.Create(Name);
            if (await _scheduler.CheckExists(jk))
            {
                bool del = await _scheduler.DeleteJob(jk);
                _logger.LogInformation($">>>    停止任务<{Name}> : {del}");
            }
            else
            {

            }
        }

        /// <summary>
        /// 停止服务
        /// </summary>
        /// <returns></returns>
        public async Task StopAsync()
        {
            if (_scheduler != null && _scheduler.IsStarted)
            {
                await _scheduler.Clear();
                await _scheduler.Shutdown();
            }
            IsStart = false;
        }
    }

    /// <summary>
    /// 调度触发器
    /// </summary>
    public class QuartzTriggerUtil
    {
        /// <summary>
        /// 创建触发器-时
        /// </summary>
        /// <param name="min"></param>
        /// <returns></returns>
        public static ITrigger CreateTriggerHours(int min)
        {
            return TriggerBuilder.Create().WithSimpleSchedule(t => t.WithIntervalInHours(min).RepeatForever()).Build();
        }

        /// <summary>
        /// 创建触发器-分
        /// </summary>
        /// <param name="min"></param>
        /// <returns></returns>
        public static ITrigger CreateTriggerMinutes(int min)
        {
            return TriggerBuilder.Create().WithSimpleSchedule(t => t.WithIntervalInMinutes(min).RepeatForever()).Build();
        }

        /// <summary>
        /// 创建触发器-秒
        /// </summary>
        /// <param name="sec"></param>
        /// <returns></returns>
        public static ITrigger CreateTriggerSeconds(int sec)
        {
            return TriggerBuilder.Create().WithSimpleSchedule(t => t.WithIntervalInSeconds(sec).RepeatForever()).Build();
        }

    }

    /// <summary>
    /// 触发时间类型
    /// </summary>
    public enum JobIntervalType
    {
        Seconds = 0x0001,
        Minutes = 0x0002,
        Hours = 0x0003,
    }
}
